﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MathNet.Numerics;

namespace k_mean_clustering
{
    public class Data
    {
        // private attributes

        protected int m_Dimension;
        protected int m_Size;
        protected double[,] m_Container;

        // generic constructor

        public Data()
        {
            m_Dimension = 0;
            m_Size = 0;
        }


        public Data(int size, int dimension)
        {
            m_Dimension = dimension;
            m_Size = size;
            m_Container = new double[m_Size, m_Dimension];
        }

        // public members

        // Accessor for dimension

        public int dimension
        {
            get
            {
                return m_Dimension;
            }
        }

        // Accessor for sample size

        public int size
        {
            get
            {
                return m_Size;
            }
        }

        // Accessor for container elements

        public double[,] container
        {
            get
            {
                return m_Container;
            }
        }

        // Display container method

        public void DisplayDataContainer()
        {
            if (m_Dimension <= 100 && m_Size <= 500)
            {
                for (int i = 0; i < m_Size; i++)
                {
                    for (int j = 0; j < m_Dimension; j++)
                        Console.WriteLine("Item [" + i + "," + j + "] = " + m_Container[i, j]);
                }

            }
            else
            {
                Console.WriteLine("Sorry, data size is too big to be displayed.");
            }
        }

        public void DisplayDataSpecs()
        {
            Console.WriteLine("Data object specifications :");
            Console.WriteLine("Dimension : " + m_Dimension);
            Console.WriteLine("Sample size : " + m_Size);
        }

        // static public function that merges two Data object into one
        // To be reviewed if dimensions do not match, use exceptions  

        static public Data merge(Data data1, Data data2)
        {
            Data merged_data = new Data(data1.m_Size + data2.m_Size, data1.m_Dimension);

            for (int j = 0; j < merged_data.m_Dimension; j++)
            {
                for (int i = 0; i < data1.m_Size; i++)
                {
                    merged_data.m_Container[i, j] = data1.m_Container[i, j];
                }
                for (int i = 0; i < data2.m_Size; i++)
                {
                    merged_data.m_Container[i + data1.m_Size, j] = data2.m_Container[i, j];
                }
            }

            return merged_data;

        }
    }
    // SimulatedUniform class simulates d-dimensional vectors of uniformly distributed numbers
    // on [lowerlimit,upperlimit]^d cube

   class SimulatedUniform : Data
    {
        protected double m_LowerLimit;
        protected double m_UpperLimit;

        public SimulatedUniform(int size, int dimension, double lower, double upper)
            : base(size, dimension)
        {
            m_Size = size;
            m_Dimension = dimension;
            m_LowerLimit = lower;
            m_UpperLimit = upper;

            var random_number = new MathNet.Numerics.Distributions.ContinuousUniform(m_LowerLimit, m_UpperLimit);
            
            for (int j = 0; j < m_Dimension; j++)
            {
                for (int i = 0; i < m_Size; i++)
                    m_Container[i, j] = random_number.Sample();
            }

        }

    }

   class SimulatedNormal : Data
   {
       protected double m_Mean;
       protected double m_StdDev;

       public SimulatedNormal(int size, int dimension, double mean, double stddev)
           : base( size, dimension)
       {
           m_Size = size;
           m_Dimension = dimension;
           m_Mean = mean;
           m_StdDev = stddev;

           var random_number = new MathNet.Numerics.Distributions.Normal(m_Mean, m_StdDev);
           for (int j = 0; j < m_Dimension; j++)
           {
               for (int i = 0; i < m_Size; i++)
                   m_Container[i, j] = random_number.Sample();
           }

       }
   }
}